package com.apestech.framework.xml.pub;

import java.util.ArrayList;

import org.apache.log4j.Logger;
import org.dom4j.Element;

import com.apestech.framework.json.JSONArray;
import com.apestech.framework.json.JSONObject;
import com.apestech.framework.xml.pub.core.ElementUtil;

/**
 * 根据XML模板生成XML数据文件
 * 入口数据格式要求,一期只支持JSONObject模式,后期会补全RowSet方式
 * @author hupo
 *
 */
public class XmlConfig extends ElementUtil {
	
	private static final Logger logger = Logger.getLogger(XmlConfig.class);
	
	private XmlDataModel xmldat=new XmlDataModel();
	private ReadXml sourcexml;
	private JSONObject   sysmap=new JSONObject();
	private JSONObject   xmlmap=new JSONObject();
	
	/**
     * XML生成主体
     * @param datalist JSONArray 外部数据,要求传入列表,即便执行数据行数只有一行也需要封装成list传入
     * @param savedir  String    保存路径,如果有系统参数out设置,这里可为目录名,如没有out,即为指定带目录的文件名
     * @throws Exception 
	 */
	public void createXml(JSONArray datalist, String savedir) throws Exception{
		WriteXml targetxml=new WriteXml();
		try {
			Element root=targetxml.createXml();
			jsonToXml(datalist, xmlmap, root);
			String path=sysmap.getString("SYS.savepath");
			targetxml.writeXml(savedir+path+".sql");
		} catch (Exception e) {
			throw new Exception(e.getMessage());
		} finally {
			targetxml=null;
		}
    }
	
	/**
	 * 内部函数,根据外部数据,依次完成对XML各结点内容编写
	 * @param datalist JSONArray  外部列表数据
	 * @param nodemap  JSONObject 源XML对应结点MAP数据
	 * @param root     Element    目标XML根结点
	 * @throws Exception
	 */
    private void jsonToXml(JSONArray datalist, JSONObject nodemap, Element root) throws Exception{
    	int len=datalist.size();
    	for(int i=0; i<len; i++){
    		JSONObject inputmap=(JSONObject) datalist.get(i);
    		jsonToXml(inputmap, nodemap.getJSONObject("content"), root);
    	}
    }
    
    /**
     * 内部函数,根据源XML指令写XML内容,注意如果没有找到符合条件值,该结点将不会显示
     * @param inputmap JSONObject 外部行数据
     * @param nodemap  JSONObject 结点MAP数据
     * @param node     Element    当前处理结点
     * @throws Exception
     */
	private void jsonToXml(JSONObject inputmap, JSONObject nodemap, Element node) throws Exception{
    	String memo="";    //备注信息,用于指导配置人员如何配置相关数据思路
		String split="";   //生成列表数据开关
		String nodeId="";  //结点ID将会用一定规则命名
		String express="";  //需要用公式解析
		String splitId="";  //获取"id:(memo)"中id部分数据
		
		ArrayList<String> list=nodemap.getKeylist();
		int len=nodemap.size();
		for(int i=0;i<len;i++){
			String key=list.get(i);
			if(!"node_attr".equals(key)){
				String node_text=getString(nodemap.getJSONObject(key).getString("node_text"));
				JSONObject attrmap=nodemap.getJSONObject(key).getJSONObject("node_attr");
				if(attrmap!=null){
		    		memo=getString(attrmap.getString("memo"));
		    		split=getString(attrmap.getString("split")); 
		    		nodeId=getString(attrmap.getString("nodeId"));
		    		express=getString(attrmap.getString("express"));
		    		splitId=getString(attrmap.getString("splitId"));
		    	}
				
				String nodekey=key;
				if(!"".equals(nodeId)){
					nodekey=getText(nodeId, inputmap); 
				}
				Element eml=getNodebyId(node,nodekey);
				if(eml==null){
					eml=node.addElement(nodekey);
				}
				if(!"".equals(memo)){
					this.setAttr(node, "memo", memo);
				}
				if(!"".equals(node_text)){
					String value=node_text;
					value=getText(value, inputmap);
					if("1".equals(splitId)){
						value=getSpiltId(value);
					} else if("1".equals(express)){
						value=(String) doExpression(value, inputmap, sysmap);
					}
					if("".equals(value)){
						removeNode(eml);
					} else {
						eml.setText(value);
					}
				} else if(!"".equals(split)){
					createList(inputmap, nodemap, eml);
				} else {
					jsonToXml(inputmap, nodemap.getJSONObject(key), eml);
				}	
			}
		}
    }
	
	/**
	 * XML列表生成逻辑,开关属性split
     * @param inputmap JSONObject 外部行数据
     * @param nodemap  JSONObject 结点MAP数据
     * @param node     Element    当前处理结点
	 * @throws Exception 
	 */
	private void createList(JSONObject inputmap, JSONObject nodemap, Element node) throws Exception{
		if(node==null) return;
		JSONObject attrmap=nodemap.getJSONObject(node.getName()).getJSONObject("node_attr");
		JSONObject formatmap=nodemap.getJSONObject(node.getName()).getJSONObject("format");
		String split=getString(attrmap.getString("split"));   //生成列表数据开关
		String splitList=getString(attrmap.getString("splitList"));  //获取"id:(memo)"中memo部分数据
		String nodeName=attrmap.getString("nodeName");  //生成列表的结点ID
		String value=attrmap.getString("value");   //用于配置生成列表数据来源数据,通常格式为带;分隔符的长字串
		value=getText(value, inputmap);
		if("1".equals(splitList)){
			value=getSplitList(value);
		}
		if(value!=null && !"".equals(value)){
			setAttr(node, "nodeName", nodeName);
			ArrayList<ArrayList<String>> list=getStrSplitList(split, value);
			int len=list.size();
			for(int i=0;i<len;i++){
				Element mxnode=node.addElement(nodeName);
				ArrayList<String> klist=formatmap.getKeylist();
				int klen=klist.size();
				for(int k=0;k<klen;k++){
					String key=klist.get(k);
					String val = formatmap.getString(key);
					ArrayList<String> zlist=(ArrayList<String>)list.get(i);
					int zlen=zlist.size();
					Boolean flag=false;
					for(int j=0;j<zlen;j++){
						if(("#{"+j+"}").equals(val)){
							flag=true;
							setElement(mxnode, key, (String)zlist.get(j));
							break;
						}
					}
					if(!flag){
						setElement(mxnode, key, val);
					}
				}
			}
		} else {
			removeNode(node);
		}
	}
	
	/**
	 * 获取源XML对应JSON值
     * @param filename String 源XML文件名
	 * @throws Exception 
	 */
	public JSONObject getSourceJson(String filename) throws Exception{
		/*xmldat.setXmlFieldName(filename);
		sourcexml=new ReadXml(xmldat);
		sourcexml.loadXmlFromFile();
		getSysmap();
		xmlmap=getNodeAttrJson(sourcexml.selectSingleNode("/YuanYuanSoftware/Template/content", ""),null,true);
		return xmlmap;*/
		return null;
	}
	
	/**
	 * 获取当前XML里系统级别的参数,XML变量以SYS.开头命名
	 * @throws Exception
	 */
	public void getSysmap() throws Exception{
		/*JSONObject map=sourcexml.getNode("/YuanYuanSoftware/Template", "");
		JSONArray list=map.getJSONArray("listNode");
		sysmap.put("SYS.attrNode", map.get("attrNode"));
		int ilen=list.size();
		for(int i=0;i<ilen;i++){
			String key=((JSONObject)list.get(i)).getString("nodeKey");  
			if(key!=null && !key.equals("content")){
				String text=sourcexml.getNodeText("/YuanYuanSoftware/Template/"+key);
				sysmap.put("SYS."+key, text);
			}
		}*/
	}
	
	/**
	 * 追加新的变量至系统函数中
     * @param inputmap JSONObject 要追加的数据
	 */
	public void addSysMap(JSONObject inputmap){
		if(inputmap!=null){
			sysmap.putAll(inputmap);
		}
	}
	
	/**
	 * 初始化sysmap值
	 * @param inputmap JSONObject 传入数据
	 */
	public void setSysText(JSONObject inputmap){
		ArrayList<String> list=sysmap.getKeylist();
		int len=list.size();
		for(int i=0; i<len; i++){
			String key=list.get(i);
			if(sysmap.get(key).getClass().getName().indexOf("JSONObject")<0){
				String text=sysmap.getString(key);
				while(hasBatisVariable(text)){
					text=getText(text, sysmap, inputmap);
				}
				sysmap.put(key, text);
			}
		}
	}
	
	/**
	 * 获取值信息
	 * @param text String      要处理的文本
	 * @param params Object... 传入不固定数量JSONOject值,根据赋值优先级传入相关数据,允许填null或者不调用
	 * @return
	 */
	private String getText(String text, Object... params){
		ArrayList<String> list=getBatisVariableList(text);
		if(list==null){
			return text;
		}
		int ilen=list.size();
		for(int i=0;i<ilen;i++){
			String Key=list.get(i);
			Object value = null;
			if("SYS.attrNode".equals(Key)){
				value=null;
			} else if(Key.indexOf("SYS.")>=0){
				value=sysmap.get(Key);
			} else {
				if(params!=null){
					int plen=params.length;
					for (int p=0;p<plen;p++){
						JSONObject map=(JSONObject) params[p];
						if(map!=null){
							value=map.get(Key);
							if(value!=null){
								break;
							}
						}
					}
				}
			}
			text=replaceBatisVariable(text, Key, value);
		}
		return text;
	}
	
}
